
`include "common_header.verilog"

//  *************************************************************************
//  File : rx_sop_align.v
//  *************************************************************************
//  This program is controlled by a written license agreement.
//  Unauthorized reproduction or use is expressly prohibited.
//  Copyright (c) 2008 MorethanIP
//  Muenchner Strasse 199, 85757 Karlsfeld, Germany
//  info@morethanip.com
//  http://www.morethanip.com
//  *************************************************************************
//  Designed by : Muhammad Anisur Rahman
//  info@morethanip.com
//  *************************************************************************
//  Decription : Alignment of SOP to lane0 (Rx)
//  Version    : $Id: rx_sop_align.v,v 1.3 2016/01/17 21:30:17 dk Exp $
//  *************************************************************************

module rx_sop_align (
   reset,
   clk,
   cgmii_rxclk_ena,
   cgmii_rxc_in,
   cgmii_rxd_in,
   xlgmii_rxt0_next_in,
   cgmii_rxc,
   cgmii_rxd,
   xlgmii_rxt0_next,
   sop_shift);

input   reset;                  //  Asynchronous Reset - clk Domain
input   clk;                    //  Receive Local Clock
input   cgmii_rxclk_ena;        //  XL/CGMII receive clock enable

input   [7:0] cgmii_rxc_in;
input   [63:0] cgmii_rxd_in;
input   xlgmii_rxt0_next_in;

output  [7:0] cgmii_rxc;        //  XL/CGMII receive control
output  [63:0] cgmii_rxd;       //  XL/CGMII receive data
output  xlgmii_rxt0_next;       //  Advance indication if TERM block without data is next after current
                                //  (directly from decoder classification block type 0x87, T0)
output  sop_shift;              //  4-Byte Column Shift of SOP

wire    [7:0] cgmii_rxc;        //  XL/CGMII receive control
wire    [63:0] cgmii_rxd;       //  XL/CGMII receive data
wire    xlgmii_rxt0_next;       //  Advance indication if TERM block without data is next after current
                                //  (directly from decoder classification block type 0x87, T0)
wire    sop_shift;

wire    det_sop0;
wire    det_sop4;
wire    det_eop4;
wire    det_eop;
wire    det_idle4;

reg     shift;
reg     det_eop_d;
reg     det_idle4_d;

reg     [3:0] cgmii_rxc_d;
reg     [31:0] cgmii_rxd_d;


assign det_sop0 = cgmii_rxd_in[7:0]   == 8'h FB && cgmii_rxc_in == 8'h 01;
assign det_sop4 = cgmii_rxd_in[39:32] == 8'h FB && cgmii_rxc_in[7:4] == 4'h 1;

assign det_eop4 = cgmii_rxd_in[39:32] == 8'h FD && cgmii_rxc_in == 8'h F0;


assign det_eop  = (cgmii_rxd_in[(8*1)-1:0*8] == 8'h FD && cgmii_rxc_in[0] == 1'b 1) |
                  (cgmii_rxd_in[(8*2)-1:1*8] == 8'h FD && cgmii_rxc_in[1] == 1'b 1) |
                  (cgmii_rxd_in[(8*3)-1:2*8] == 8'h FD && cgmii_rxc_in[2] == 1'b 1) |
                  (cgmii_rxd_in[(8*4)-1:3*8] == 8'h FD && cgmii_rxc_in[3] == 1'b 1) |
                  (cgmii_rxd_in[(8*5)-1:4*8] == 8'h FD && cgmii_rxc_in[4] == 1'b 1) |
                  (cgmii_rxd_in[(8*6)-1:5*8] == 8'h FD && cgmii_rxc_in[5] == 1'b 1) |
                  (cgmii_rxd_in[(8*7)-1:6*8] == 8'h FD && cgmii_rxc_in[6] == 1'b 1) |
                  (cgmii_rxd_in[(8*8)-1:7*8] == 8'h FD && cgmii_rxc_in[7] == 1'b 1);

assign det_idle4 = cgmii_rxd_in[63:32] == 32'h 07070707 && cgmii_rxc_in[7:4] == 4'b 1111;


always @(posedge reset or posedge clk)
   begin : process_1
   if (reset == 1'b 1)
      begin
      shift       <= 1'b 0;
      det_eop_d   <= 1'b 0;
      det_idle4_d <= 1'b 0;
      end
   else
      begin
      if(cgmii_rxclk_ena == 1'b 1)
         begin
         det_eop_d   <= det_eop;
         det_idle4_d <= det_idle4;

         if (det_sop4 == 1'b 1)
            begin
            shift <= 1'b 1;
            end
         else if (det_eop_d == 1'b 1 | det_idle4_d == 1'b 1 | det_sop0 == 1'b 1)
            begin
            shift <= 1'b 0;
            end
         end
      end
   end


always @(posedge reset or posedge clk)
   begin : process_2
   if (reset == 1'b 1)
      begin
      cgmii_rxc_d <= 4'd 0;
      cgmii_rxd_d <= 32'd 0;
      end
   else
      begin
      if(cgmii_rxclk_ena == 1'b 1)
         begin
         cgmii_rxc_d <= cgmii_rxc_in[7:4];
         cgmii_rxd_d <= cgmii_rxd_in[63:32];
         end
      end
   end


assign cgmii_rxd[63:32] = (det_sop4 == 1'b 1)                   ? 32'h 07070707 :
                          (shift == 1'b 1 && det_sop0 == 1'b 0) ? cgmii_rxd_in[31:0] :
                                                                  cgmii_rxd_in[63:32];

assign cgmii_rxd[31:0]  = (shift == 1'b 1 && det_sop0 == 1'b 0) ? cgmii_rxd_d :
                                                                  cgmii_rxd_in[31:0];

assign cgmii_rxc[7:4]   = (det_sop4 == 1'b 1)                   ? 4'b 1111 :
                          (shift == 1'b 1 && det_sop0 == 1'b 0) ? cgmii_rxc_in[3:0] :
                                                                  cgmii_rxc_in[7:4];

assign cgmii_rxc[3:0]   = (shift == 1'b 1 && det_sop0 == 1'b 0) ? cgmii_rxc_d :
                                                                  cgmii_rxc_in[3:0];

assign xlgmii_rxt0_next = (shift == 1'b 1) ? det_eop4 : xlgmii_rxt0_next_in;

assign sop_shift = (shift == 1'b 1 && det_sop0 == 1'b 0) ? 1'b 1 : 1'b 0;

endmodule // module rx_sop_align
